iT邦幫忙

2025 iThome 鐵人賽

DAY 21
2

在前面Vuex資料流中呼叫actions時,其中一個步驟,即EmployeeService.query(params),乃是向API請求資料,相關步驟程式碼位置如下:

// src/store/employee.module.js
import { EmployeeService } from "@/common/api.service";

async [FETCH_EMPLOYEES](context, params) {
  context.commit(SET_LOADING, true);
  try {
    const { data } = await EmployeeService.query(params); // 呼叫API拿資料
		...
		
  } catch (err) {
		...
		
  } finally {
		...
		
  }
}

不同於Vuex狀態管理檔案,主要放置於src/store,該API請求檔案,乃放置於src/common/api.service.js,以下提供簡易Vue專案結構供區分參考。

vue-app-project/
├─ public/
├─ src/
│  ├─ common/                # 放置共享資源,如共用元件、工具類程式、服務類程式
│  │  ├─ api.service.js        # API請求相關程式碼
│  ├─ store/                 # 放置狀態管理,如Vuex相關檔案
│  │  ├─ employee.module.js    # employee模組物件

打開api.service.js檔案,相關程式碼參考如下:

// src/common/api.service.js
import Vue from "vue";
import axios from "axios";
import VueAxios from "vue-axios";
import { API_URL } from "@/common/config";

// 封裝axios相關設定與基礎操作(如query)
const ApiService = {

  // 初始化,註冊axios作為Vue插件,並設定預設baseURL
  init() {
    Vue.use(VueAxios, axios);
    Vue.axios.defaults.baseURL = API_URL;
  },

  // 組成GET請求的完整網址,並用axios.get()發送請求
  // 這是EmployeeService.query()背後真正執行的方法
  query(resource, params) {
  
	// 驗證參數是否為物件,確保URL查詢字串能正確組成
    if (typeof params !== "object") {
      throw new Error(`[ApiService] params 必須是物件,你傳的是:${typeof params}`);
    }
    
    // 將參數物件(params)轉為查詢字串,不直接使用,可用於除錯
    // 查詢字串,舉例如:page=1&page_size=10
    const queryString = new URLSearchParams(params).toString();
    
    // 組出完整請求網址,不直接使用,可用於除錯
    // 完整請求網址,舉例如:
    // https://api.example.com/employee/?page=1&page_size=10
    const fullUrl = `${Vue.axios.defaults.baseURL}${resource}?${queryString}`;
    console.log(`QUERY 請求網址:`, fullUrl);

	// 真正送出並執行GET請求,params會自動被axios加入為「?key=value」格式之查詢參數
    return Vue.axios.get(resource, { params }).catch((error) => {
      throw new Error(`[RWV] ApiService ${error}`);
    });
  },

};

export default ApiService;

// 封裝「與員工相關」的API呼叫
export const EmployeeService = {

  // 取得員工列表,可帶分頁或篩選參數(params)
  // 實際上就是呼叫ApiService.query(),但固定resource為"employee/"
  query(params) {
    return ApiService.query("employee/", params);
  },
  
};

其中可以發現EmployeeService.query(params),其實還另外呼叫ApiService.query(resource, params),進行API服務,此乃封裝axios的共同邏輯,並讓各領域服務,如Employee,統一透過它發送API請求。

進一步介紹,axios是一個用於發送HTTP請求的JavaScript庫,可完成跟後端API請求及發送資料的功能,包括GET、POST、PUT、DELETE基本功能,並可接收回傳資料。

EmployeeService藉由固定resource為”employee/”,僅針對員工相關API,如query(params),進行呼叫,以集中區分管理,因此Vuex模組物件只要呼叫EmployeeService,而不用理會其中的底層邏輯。

在設定ApiService之前,需要進行初始化,將axios註冊作為Vue插件,並設定預設baseURL,提供API請求位址。需要注意的是,於專案啟動時,在src/main.js中需要呼叫ApiService.init(),以進行ApiService的設定。

// src/main.js
import ApiService from "./common/api.service";

ApiService.init();

ApiService .query(resource, params),乃使用典型的axios.get()+查詢參數的API請求。

  • 首先乃進行參數驗證,以避免非物件類型的參數,導致queryString組合出錯。
  • 另外,使用URLSearchParams()queryString所組合出的查詢字串fullUrl,只用於除錯,可供給console.log()輸出,以達到可解釋性除錯。
  • 實際的API請求還是交給axios.get()進行,axios會自動把{ params }物件轉成URL查詢參數,並處理URL編碼,如空格、特殊符號等,如此可確保正確編碼,並順利取得所回傳的資料。
const ApiService = {

	// 組成GET請求的完整網址,並用axios.get()發送請求
	// 這是EmployeeService.query()背後真正執行的方法
  query(resource, params) {
  
	// 驗證參數是否為物件,確保URL查詢字串能正確組成
    if (typeof params !== "object") {
      throw new Error(`[ApiService] params 必須是物件,你傳的是:${typeof params}`);
    }
    
    // 將參數物件(params)轉為查詢字串,不直接使用,可用於除錯
    // 查詢字串,舉例如:page=1&page_size=10
    const queryString = new URLSearchParams(params).toString();
    
    // 組出完整請求網址,不直接使用,可用於除錯
    // 完整請求網址,舉例如:
    // https://api.example.com/employee/?page=1&page_size=10
    const fullUrl = `${Vue.axios.defaults.baseURL}${resource}?${queryString}`;
    console.log(`QUERY 請求網址:`, fullUrl);

	// 真正送出並執行GET請求,params會自動被axios加入為「?key=value」格式之查詢參數
    return Vue.axios.get(resource, { params }).catch((error) => {
      throw new Error(`[RWV] ApiService ${error}`);
    });
  },

};

閱讀到此,其實先前在組件中以dispatch()所呼叫的action,本質上仍然是透過axios向後端API發送請求,只是先將axios行為統一封裝成ApiService,讓各不同領域組件可共同使用,並以固定resource的方式進行細分服務,達到區分管理的作用,並可使Vuex模組物件能方便、簡潔地進行後端API請求。

最後,提供一個小技巧,在src/common/api.service.js檔案中,所使用到的API請求網址,因為涉及到各資訊安全防護等敏感議題,因此我們通常都是從外部檔案,如src/common/config.js,引入API_URL常數,這樣的好處除了可以集中管理環境設定,並在不同環境(開發、測試、正式)切換時更方便,並且因該外部檔案通常會設定不公開,如此在公開的api.service.js檔案中,就可以避免伺服器位址暴露的風險。不過需注意,前端打包後的API_URL還是能被看到,若有真正高敏感資料,仍應該放在後端環境變數中處理。


上一篇
Day 20: Vue字串管理及命名空間(namespaced)
下一篇
Day 22: Vue跨組件資料傳遞 props及emits
系列文
從零打造網頁系統:非資訊人也能完成的全端專題實作22
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言